import _ from 'lodash'
import Konva from 'konva'
import ebus from './ebus.js'

var windowImg = new Image()
windowImg.src = require('../assets/img/vidbg.jpg')

const g_dftFontSize = 12

function setLcdMultiScreen(layer, cfg) {
  let screenWidth = cfg.width / cfg.multiScreenX
  let screenHeight = cfg.height / cfg.multiScreenY

  //画一个最外层的大框框，N*（12组成格子）的那种
  var node = new Konva.Rect({
    x: 0,
    y: 0,
    width: cfg.width,
    height: cfg.height,
    stroke: '#000',
    strokeWidth: 2
  })
  layer.add(node)    

  //最外层的大框框里画横向分割线
  if (cfg.multiScreenX > 1) {
    for (let i = 1; i < cfg.multiScreenX; i++) {
      var node = new Konva.Rect({
        x: screenWidth * i - 2,
        y: 0,
        width: 2,
        height: cfg.height,
        fill: '#000'
      })
      layer.add(node)
    }
  }
  //最外层的大框框里画竖向分割线
  if (cfg.multiScreenY > 1) {
    for (let i = 1; i < cfg.multiScreenY; i++) {
      var node = new Konva.Rect({
        x: 0,
        y: screenHeight * i - 2,
        width: cfg.width,
        height: 2,
        fill: '#000'
      })
      layer.add(node)
    }
  }  
}

export function drawLcd(layer, cfg) {
  var node = new Konva.Rect({
    x: 0,
    y: 0,
    width: cfg.width,
    height: cfg.height,
    stroke: '#000',
    strokeWidth: 2
  })
  layer.add(node)   
  layer.draw()
}

//画1/12的那种小格子
export function drawLayoutGrid(layer, cfg) {
  let unitXCnt = cfg.unitXCnt
  let unitYCnt = cfg.unitYCnt
  let unitWidth = cfg.unitWidth
  let unitHeight = cfg.unitHeight
  var unitRectAttrs = {
    x: 0,
    y: 0,
    width: unitWidth - 0.5,
    height: unitHeight - 0.5,
    stroke: '#EEE',
    strokeWidth: 1
  }
  var textAttrs = {
    x: 0,
    y: 0,
    fontSize: 10,
    text: '',
    fill: 'blue'
  }  

  //把1~12填入1/12的小格子，横向和纵向
  for (var i = 0; i < unitXCnt; i++) {
    for (var j = 0; j < unitYCnt; j++) {
      unitRectAttrs.x = unitWidth * i
      unitRectAttrs.y = unitHeight * j
      var node = new Konva.Rect(unitRectAttrs)
      layer.add(node)

      if ((i % 12 === 0)
        || (j % 12 === 0)) {
        textAttrs.x = unitRectAttrs.x + (unitRectAttrs.width / 2)
        textAttrs.y = unitRectAttrs.y + (unitRectAttrs.height / 2)
        if (i % 12 === 0) {
          textAttrs.text = `${(j % 12) + 1}`
        } else if (j % 12 === 0) {
          textAttrs.text = `${(i % 12) + 1}`
        }
        var node = new Konva.Text(textAttrs)
        node.setOffset({
          x: node.getWidth() / 2,
          y: node.getHeight() / 2,
        })
        layer.add(node)
      }
    }
  }

  setLcdMultiScreen(layer, cfg)
  layer.draw()
}

function getWindowRectWithCfg(rect, cfg) {
  var windowRect = {}
  let xEnd = 0; let yEnd = 0;
  if (rect.width < 0) {
    rect.x += rect.width
    rect.width = Math.abs(rect.width)
  }
  if (rect.height < 0) {
    rect.y += rect.height
    rect.height = Math.abs(rect.height)
  }
  var timesX = 1;//精确度
  var timesY = 1;//精确度
  if(cfg.multiScreenX > 5){
    windowRect.x = Math.floor(rect.x / (cfg.unitWidth * 2)) * cfg.unitWidth * 2
    xEnd = Math.ceil((rect.x + rect.width) / (cfg.unitWidth * 2)) * cfg.unitWidth * 2
  }
  else{
    windowRect.x = Math.floor(rect.x / cfg.unitWidth) * cfg.unitWidth
    xEnd = Math.ceil((rect.x + rect.width) / (cfg.unitWidth)) * cfg.unitWidth
  }
  if(cfg.multiScreenY > 5){
    windowRect.y = Math.floor(rect.y / (cfg.unitHeight * 2)) * cfg.unitHeight * 2
    yEnd = Math.ceil((rect.y + rect.height) / (cfg.unitHeight * 2)) * cfg.unitHeight * 2
  }
  else{
    windowRect.y = Math.floor(rect.y / cfg.unitHeight) * cfg.unitHeight
    yEnd = Math.ceil((rect.y + rect.height) / cfg.unitHeight) * cfg.unitHeight
  }

  // windowRect.x = Math.floor(rect.x / cfg.unitWidth) * cfg.unitWidth
  // windowRect.y = Math.floor(rect.y / cfg.unitHeight) * cfg.unitHeight
  // let xEnd = Math.ceil((rect.x + rect.width) / (cfg.unitWidth)) * cfg.unitWidth
  // let yEnd = Math.ceil((rect.y + rect.height) / cfg.unitHeight) * cfg.unitHeight
  windowRect.width = xEnd - windowRect.x
  windowRect.height = yEnd - windowRect.y
  return windowRect
}

function addWindowAnchor(window, x, y, name) {
  let group = window.group
  let stage = group.getStage()
  let layer = group.getLayer()

  let anchor = new Konva.Circle({
    x: x,
    y: y,
    stroke: '#666',
    fill: '#ddd',
    strokeWidth: 2,
    radius: 8,
    name: name,
    draggable: true,
    dragOnTop: false
  })

  anchor.dragBoundFunc(function(pos) {
    let minX = 0
    let minY = 0
    let maxX = stage.width()
    let maxY = stage.height()
    var x = pos.x < minX ? minX : pos.x
    var y = pos.y < minY ? minY : pos.y
    x = x > maxX ? maxX : x
    y = y > maxY ? maxY : y
    return {
      x,
      y
    }
  }) 

  anchor.window = window

  group.add(anchor)
}

function updateWindowRect(window, rect, cfg) {
  var windowRect = window.windowRect
  let newWindowRect = getWindowRectWithCfg(rect, cfg)

  windowRect.x = newWindowRect.x
  windowRect.y = newWindowRect.y
  windowRect.width = newWindowRect.width
  windowRect.height = newWindowRect.height
}

function reviseChangeWindow(stage, rect) {
  if (rect.x < 0) {
    rect.x = 0
  }
  if (rect.x + rect.width > stage.width()) {
    rect.width = stage.width() - rect.x
  }
  if (rect.y < 0) {
    rect.y = 0
  }
  if (rect.y + rect.height > stage.height()) {
    rect.height = stage.height() - rect.y
  }
}

function updateAnchor(activeAnchor, isEnd) {
  let group = activeAnchor.getParent()
  let stage = group.getStage()
  let userdata = stage.userdata
  let cfg = userdata.cfg
  let window = activeAnchor.window

  let topLeft = group.find('.topLeft')[0]
  let topRight = group.find('.topRight')[0]
  let bottomRight = group.find('.bottomRight')[0]
  let bottomLeft = group.find('.bottomLeft')[0]
  let image = group.find('Image')[0]
  let rect = group.find('Rect')[0]
  let text = undefined
  if (cfg.showWindowSrc) {
    text = group.find('Text')[0]
  }

  let anchorX = activeAnchor.getX()
  let anchorY = activeAnchor.getY()

  // update anchor positions
  switch (activeAnchor.getName()) {
    case 'topLeft':
      topRight.setY(anchorY)
      bottomLeft.setX(anchorX)
      break
    case 'topRight':
      topLeft.setY(anchorY)
      bottomRight.setX(anchorX)
      break
    case 'bottomRight':
      bottomLeft.setY(anchorY)
      topRight.setX(anchorX)
      break
    case 'bottomLeft':
      bottomRight.setY(anchorY)
      topLeft.setX(anchorX)
      break
  }

  image.position(topLeft.position())
  rect.position(topLeft.position())

  var width = topRight.getX() - topLeft.getX()
  var height = bottomLeft.getY() - topLeft.getY()
  if (width && height) {
    image.width(width)
    image.height(height)
    rect.width(width)
    rect.height(height)
    text && text.width(width)
    text && text.y((height - g_dftFontSize) / 2)
  }

  if (isEnd) {
    var groupRect = {
      x: group.x() + image.x(),
      y: group.y() + image.y(),
      width: image.width(),
      height: image.height()      
    }
    //reviseChangeWindow(stage, groupRect)
    updateWindowRect(window, groupRect, cfg)
  }
}

function addWindowAnchorEvent(anchor) {
  anchor.on('dragmove', function(evt) {
    if (evt.target === this) {
      let layer = this.getLayer()
      updateAnchor(this, false)
      layer.draw()
    }
  })
  anchor.on('mousedown touchstart', function() {
    let group = this.getParent()
    group.setDraggable(false)
    this.moveToTop()
  })
  anchor.on('dragend', function() {
    let group = this.getParent()
    group.setDraggable(true)
    updateAnchor(this, true)
    //规避改变大小后，group的drag bound失效问题
    this.off('mouseover mouseout')
    ebus.emit('layout-reset-lcd')
  })
  // add hover styling
  anchor.on('mouseover', function() {
    let layer = this.getLayer()
    //document.body.style.cursor = 'pointer'
    this.setStrokeWidth(4)
    layer.draw()
  })
  anchor.on('mouseout', function() {
    let layer = this.getLayer()
    //document.body.style.cursor = 'default'
    this.setStrokeWidth(2)
    layer.draw()
  })
}

function delWindowAnchorEvent(anchor) {
  anchor.off('dragmove')
  anchor.off('mousedown touchstart')
  anchor.off('dragend')
  anchor.off('mouseover')
  anchor.off('mouseout')
}

function addWindowAnchors(window) {
  let windowRect = window.windowRect
  addWindowAnchor(window, 0, 0, 'topLeft')
  addWindowAnchor(window, windowRect.width, 0, 'topRight')
  addWindowAnchor(window, windowRect.width, windowRect.height, 'bottomRight')
  addWindowAnchor(window, 0, windowRect.height, 'bottomLeft') 
}

function drawLcdWindow(stage, layer, window) {
  let windowRect = window.windowRect
  let windowCfg = window.windowCfg
  var userdata = stage.userdata
  let cfg = userdata.cfg

  var group = new Konva.Group({
    x: windowRect.x,
    y: windowRect.y,
    name: 'window',
    draggable: false
  })
  layer.add(group)

  var attrs = {
    width: windowRect.width,
    height: windowRect.height,
    image: windowImg,
    opacity: 0.8
  }
  var node = new Konva.Image(attrs)
  group.add(node)

  if (cfg.showWindowSrc && windowCfg) {
    var showText = `${windowCfg.windowId}`
    if (windowCfg.srcName) {
      showText += '-' + windowCfg.srcName
    }
    var attrs = {
      width: windowRect.width,
      y: (windowRect.height - g_dftFontSize) / 2,
      text: showText,
      fill: '#000', //black
      align: 'center',
    }
    var node = new Konva.Text(attrs)
    group.add(node)    
  }

  var attrs = {
    width: windowRect.width,
    height: windowRect.height,
    stroke: 'gray',
    opacity: 0.8
  }
  var rect = new Konva.Rect(attrs)
  group.add(rect)
  
  rect.on('dblclick', e => {
    rect.destroy()
    layer.draw()
  })

  group.dragBoundFunc(function(pos) {
    let minX = - (windowRect.width * 2 / 3)
    let minY = - (windowRect.height * 2 / 3)
    let maxX = stage.width() - (windowRect.width / 3)
    let maxY = stage.height() - (windowRect.height / 3)
    var x = pos.x < minX ? minX : pos.x
    var y = pos.y < minY ? minY : pos.y
    x = x > maxX ? maxX : x
    y = y > maxY ? maxY : y
    return {x, y}
  })

  window.group = group

  addWindowAnchors(window)
}

function newLcdWindow(stage, layer, windowRect, windowCfg) {
  var userdata = stage.userdata
  let cfg = userdata.cfg

  var window = {
    windowRect: windowRect,
    windowCfg: windowCfg
  }

  drawLcdWindow(stage, layer, window)
  userdata.windows.push(window)
}

export function openWindow(stage, layer, windowCfg) {
  var userdata = stage.userdata
  let cfg = userdata.cfg
  let coordinate = windowCfg.coordinate
  var windowRect = {
    x: coordinate.left * cfg.unitWidth,
    y: coordinate.top * cfg.unitHeight,
    width: (coordinate.right - coordinate.left) * cfg.unitWidth,
    height: (coordinate.bottom - coordinate.top) * cfg.unitHeight,
  }

  newLcdWindow(stage, layer, windowRect, windowCfg) 
  layer.draw() 
}

export function delAllWindows(stage, layer) {
  var userdata = stage.userdata

  _.forEach(userdata.windows, function(item) {
    item.group.destroy()
    item.group = undefined
  })

  userdata.windows = []

  layer.draw()
}

export function updateWindows(stage, layer) {
  var userdata = stage.userdata

  _.forEach(userdata.windows, function(item) {
    item.group.destroy()
    item.group = undefined
  })  

  _.forEach(userdata.windows, function(item) {
    drawLcdWindow(stage, layer, item)
  })

  addSetWindowEvent(stage)
  layer.draw()
}

export function addNewWindowEvent(stage, layer) {
  var userdata = stage.userdata
  let cfg = userdata.cfg

  stage.on('mousedown', function(e) {
    if (!userdata.select) {
      var attrs = {
        x: e.evt.offsetX,
        y: e.evt.offsetY,
        width: 0,
        height: 0,
        stroke: 'red',
        fill: 'green',
        opacity: 0.5
      }
      userdata.select = new Konva.Rect(attrs)
      layer.add(userdata.select)        
    }
  })  
  stage.on('mousemove', function(e) {
    var select = userdata.select
    if (select) {
      select.size({
        width: e.evt.offsetX - select.getAttr('x'),
        height: e.evt.offsetY - select.getAttr('y'),
      })
      layer.draw()
    }
  }) 
  stage.on('mouseleave', function(e) {
    layer.fire('mouseup')
  })
  stage.on('mouseup', function(e) {
    var select = userdata.select
    var windows = userdata.windows
    if (select) {
      let windowRect = getWindowRectWithCfg(select.getAttrs(), cfg)
      if (windowRect && windows.length < cfg.maxWindowCnt) {
        newLcdWindow(stage, layer, windowRect, null)
      }
      select.destroy()
      layer.draw()
      userdata.select = undefined
    }
    ebus.emit('layout-new-window-end')
  }) 
}

export function delNewWindowEvent(stage) {
  stage.off('mousedown')
  stage.off('mousemove')
  stage.off('mouseleave')
  stage.off('mouseup')
}

function checkIfDelWindow(window) {
  let group = window.group
  let stage = group.getStage()
  let windowRect = window.windowRect

  //TODO windowRect change
  let minX1 = - (windowRect.width / 3)
  let minY1 = - (windowRect.height / 3)
  let maxX1 = stage.width() - (windowRect.width * 2 / 3)
  let maxY1 = stage.height() - (windowRect.height * 2/ 3)

  let dragWidth = windowRect.width / 2
  let dragHeight = windowRect.height / 2
  let minX2 = - dragWidth
  let minY2 = - dragHeight
  let maxX2 = stage.width() - dragWidth
  let maxY2 = stage.height() - dragHeight

  let x = group.x()
  let y = group.y()

  if (((x <= minX1) 
    || (x >= maxX1))
    && ((y <= minY1)
    || (y >= maxY1))) {
    //x和y都超过1/3
    return true
  } else if ((x <= minX2)
    || (x >= maxX2)
    || (y <= minY2)
    || (y >= maxY2)) {
    //x或y超过1/2
    return true
  } else {
    return false
  }
}  

function reviseDragWindow(window, cfg) {
  let group = window.group
  let stage = group.getStage()
  let image = group.find('Image')[0]
  var windowRect = window.windowRect  

  let x = group.x()
  let y = group.y()

  if (x < 0) {
    windowRect.x = 0
  } else if (x + image.width() > stage.width()) {
    windowRect.x = stage.width() - image.width()
  } else {
    if ((x % cfg.unitWidth) >= (cfg.unitWidth / 2)) {
      windowRect.x = Math.ceil(x / cfg.unitWidth) * cfg.unitWidth
    } else {
      windowRect.x = Math.floor(x / cfg.unitWidth) * cfg.unitWidth
    }
  }

  if (y < 0) {
    windowRect.y = 0
  } else if (y + image.height() > stage.height()) {
    windowRect.y = stage.height() - image.height()
  } else {
    if ((y % cfg.unitHeight) >= (cfg.unitHeight / 2)) {
      windowRect.y = Math.ceil(y / cfg.unitHeight) * cfg.unitHeight
    } else {
      windowRect.y = Math.floor(y / cfg.unitHeight) * cfg.unitHeight
    }
  }

  ebus.emit('layout-reset-lcd')
}

export function addSetWindowEvent(stage) {
  let userdata = stage.userdata
  let cfg = userdata.cfg

  _.forEach(userdata.windows, function(item, index) {
    let group = item.group
    let layer = group.getLayer()

    group.on('dragend', function(e) {
      if (checkIfDelWindow(item)) {
        group.destroy()
        layer.draw()
        userdata.windows.splice(index, 1)
      } else {
        reviseDragWindow(item, cfg)
      }
    })

    group.setDraggable(true)

    _.forEach(group.find('Circle'), function(anchor) {
      addWindowAnchorEvent(anchor)
    })
  }.bind(this))
}

export function delSetWindowEvent(stage) {
  let userdata = stage.userdata
  _.forEach(userdata.windows, function(item) {
    item.group.off('dragend')
    item.group.setDraggable(false)
    _.forEach(item.group.find('Circle'), function(anchor) {
      delWindowAnchorEvent(anchor)
    })
  })
}

export function getWindowList(stage) {
  let userdata = stage.userdata
  let cfg = userdata.cfg
  var windowList = []

  _.forEach(userdata.windows, function(item, index) {
    let windowRect = item.windowRect

    windowList.splice(windowList.length, 0, {
      windowId: index + 1,
      layer: index + 1,
      coordinate: {
        left: Math.round(windowRect.x / cfg.unitWidth),
        top: Math.round(windowRect.y / cfg.unitHeight),
        right: Math.round((windowRect.x + windowRect.width) / cfg.unitWidth),
        bottom: Math.round((windowRect.y + windowRect.height) / cfg.unitHeight)        
      }
    })
  })

  return windowList
}

export function getWindowListCnt(stage) {
  let userdata = stage.userdata
  return userdata.windows.length
}

function checkOneWindowOverlay(windows, index) {
  let currWindowRect = windows[index].windowRect

  for (var i = index + 1; i < windows.length; i++) {
    let upperWindowRect = windows[i].windowRect
    if ((upperWindowRect.x <= currWindowRect.x)
      && (upperWindowRect.y <= currWindowRect.y)
      && (upperWindowRect.x + upperWindowRect.width >= currWindowRect.x + currWindowRect.width)
      && (upperWindowRect.y + upperWindowRect.height >= currWindowRect.y + currWindowRect.height)) {
      console.log('currWindowRect:' + JSON.stringify(currWindowRect))
      console.log('upperWindowRect:' + JSON.stringify(upperWindowRect))
      return true
    }
  }

  return false 
}

export function checkWindowOverlay(stage) {
  let userdata = stage.userdata
  let windows = userdata.windows

  for (var i = 0; i < windows.length - 1; i++) {
    if (checkOneWindowOverlay(windows, i)) {
      return true
    }
  }

  return false
}